package com.gzc.just.play.last.war.sceneserver.benchmark;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import static org.junit.jupiter.api.Assertions.*;

/**
 * AI决策性能基准测试
 * 
 * 测试目标:
 * - AI决策: 5,000 ops/sec
 * - 平均延迟: < 200μs
 * - 99% 延迟: < 1ms
 */
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Thread)
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(value = 1)
public class AIDecisionBenchmark {
    
    private Random random = new Random();
    private Map<Integer, AIUnit> aiUnits = new ConcurrentHashMap<>();
    private Map<Integer, Player> players = new HashMap<>();
    private Map<Integer, NPC> npcs = new HashMap<>();
    private AIManager aiManager;
    
    @BeforeEach
    public void setup() {
        aiManager = new AIManager();
        
        // 初始化玩家
        for (int i = 0; i < 20; i++) {
            Player player = new Player(3000 + i, "Player" + i, 40 + random.nextInt(20), 
                800 + random.nextInt(400), 50.0f + random.nextFloat() * 50.0f, 
                30.0f + random.nextFloat() * 30.0f);
            players.put(player.id, player);
        }
        
        // 初始化NPC
        for (int i = 0; i < 50; i++) {
            NPC npc = new NPC(4000 + i, "NPC" + i, 35 + random.nextInt(30), 
                500 + random.nextInt(500), 
                NPCBehavior.values()[random.nextInt(NPCBehavior.values().length)]);
            npcs.put(npc.id, npc);
            
            // 为NPC创建AI单位
            AIUnit aiUnit = new AIUnit(npc.id, npc.behavior, 3.0f + random.nextFloat() * 2.0f);
            aiUnits.put(npc.id, aiUnit);
            aiManager.addAIUnit(aiUnit);
        }
    }
    
    @Benchmark
    public AIDecision benchmarkBasicDecision() {
        // 基础AI决策
        int unitId = random.nextInt(50) + 4000; // NPC ID范围
        AIUnit unit = aiUnits.get(unitId);
        
        if (unit == null) {
            return AIDecision.IDLE;
        }
        
        // 根据行为类型做出决策
        switch (unit.behavior) {
            case AGGRESSIVE:
                return random.nextFloat() < 0.7f ? AIDecision.ATTACK : AIDecision.MOVE_FORWARD;
            case DEFENSIVE:
                return random.nextFloat() < 0.8f ? AIDecision.DEFEND : AIDecision.MOVE_BACKWARD;
            case PASSIVE:
                return random.nextFloat() < 0.9f ? AIDecision.IDLE : AIDecision.MOVE_RANDOM;
            case PATROL:
                return random.nextFloat() < 0.6f ? AIDecision.MOVE_FORWARD : AIDecision.TURN;
            default:
                return AIDecision.IDLE;
        }
    }
    
    @Benchmark
    public AIDecision benchmarkThreatAssessment() {
        // 威胁评估决策
        int unitId = random.nextInt(50) + 4000;
        AIUnit unit = aiUnits.get(unitId);
        
        if (unit == null) {
            return AIDecision.IDLE;
        }
        
        // 模拟威胁评估
        float threatLevel = random.nextFloat();
        
        if (threatLevel > 0.8f) {
            return AIDecision.ATTACK;
        } else if (threatLevel > 0.5f) {
            return AIDecision.DEFEND;
        } else if (threatLevel > 0.2f) {
            return AIDecision.MOVE_BACKWARD;
        } else {
            return AIDecision.IDLE;
        }
    }
    
    @Benchmark
    public Player benchmarkTargetSelection() {
        // 目标选择
        int unitId = random.nextInt(50) + 4000;
        AIUnit unit = aiUnits.get(unitId);
        
        if (unit == null || players.isEmpty()) {
            return null;
        }
        
        // 简化目标选择：选择距离最近的玩家
        Player target = null;
        float minDistance = Float.MAX_VALUE;
        
        for (Player player : players.values()) {
            float distance = calculateDistance(unitId, player.id);
            if (distance < minDistance && distance < unit.sightRange) {
                minDistance = distance;
                target = player;
            }
        }
        
        return target;
    }
    
    private float calculateDistance(int unitId, int playerId) {
        // 简化的距离计算
        return random.nextFloat() * 100.0f;
    }
    
    @Benchmark
    public Skill benchmarkSkillSelection() {
        // 技能选择
        int unitId = random.nextInt(50) + 4000;
        AIUnit unit = aiUnits.get(unitId);
        
        if (unit == null) {
            return null;
        }
        
        // 根据情况选择技能
        float healthRatio = random.nextFloat();
        
        if (healthRatio > 0.7f) {
            return Skill.HEAL;
        } else if (healthRatio > 0.3f) {
            return Skill.ATTACK;
        } else if (healthRatio < 0.1f) {
            return Skill.ESCAPE;
        } else {
            return Skill.DEFEND;
        }
    }
    
    @Benchmark
    public List<AIDecision> benchmarkDecisionSequence() {
        // 决策序列
        List<AIDecision> decisions = new ArrayList<>();
        
        for (int i = 0; i < 3; i++) { // 生成3个连续决策
            decisions.add(benchmarkBasicDecision());
        }
        
        return decisions;
    }
    
    @Benchmark
    public boolean benchmarkCooldownManagement() {
        // 冷却管理
        int unitId = random.nextInt(50) + 4000;
        AIUnit unit = aiUnits.get(unitId);
        
        if (unit == null) {
            return true;
        }
        
        long currentTime = System.currentTimeMillis();
        boolean isReady = false;
        
        // 检查技能冷却
        if (unit.lastActionTime + unit.cooldownTime <= currentTime) {
            unit.lastActionTime = currentTime;
            isReady = true;
        }
        
        return isReady;
    }
    
    @Benchmark
    public AIDecision benchmarkGroupCoordination() {
        // 群体协调决策
        int unitId = random.nextInt(50) + 4000;
        AIUnit unit = aiUnits.get(unitId);
        
        if (unit == null) {
            return AIDecision.IDLE;
        }
        
        // 检查附近友军
        int nearbyAllies = 0;
        for (AIUnit other : aiUnits.values()) {
            if (other.id != unitId && calculateDistance(unitId, other.id) < 20.0f) {
                nearbyAllies++;
            }
        }
        
        // 根据友军数量调整决策
        if (nearbyAllies >= 3) {
            return AIDecision.ATTACK; // 群体进攻
        } else if (nearbyAllies == 0) {
            return AIDecision.MOVE_BACKWARD; // 孤立后退
        } else {
            return benchmarkBasicDecision(); // 正常决策
        }
    }
    
    @Benchmark
    public void benchmarkAIUpdate() {
        // AI状态更新
        int unitId = random.nextInt(50) + 4000;
        AIUnit unit = aiUnits.get(unitId);
        
        if (unit == null) {
            return;
        }
        
        // 更新AI状态
        unit.lastUpdateTime = System.currentTimeMillis();
        
        // 执行决策
        AIDecision decision = benchmarkBasicDecision();
        
        // 更新行动历史
        unit.lastAction = decision;
        
        // 更新冷却
        if (!benchmarkCooldownManagement()) {
            // 技能冷却中，执行其他行动
            return;
        }
    }
    
    @Benchmark
    public Map<Integer, AIDecision> benchmarkBatchAIUpdate() {
        // 批量AI更新
        Map<Integer, AIDecision> decisions = new HashMap<>();
        int batchSize = 10; // 每次更新10个单位
        
        for (int i = 0; i < batchSize; i++) {
            int unitId = random.nextInt(50) + 4000;
            AIUnit unit = aiUnits.get(unitId);
            
            if (unit != null) {
                decisions.put(unitId, benchmarkBasicDecision());
            }
        }
        
        return decisions;
    }
    
    // 简化的内部类
    private static class AIUnit {
        int id;
        NPCBehavior behavior;
        float sightRange;
        long lastActionTime;
        long cooldownTime;
        long lastUpdateTime;
        AIDecision lastAction;
        
        public AIUnit(int id, NPCBehavior behavior, float sightRange) {
            this.id = id;
            this.behavior = behavior;
            this.sightRange = sightRange;
            this.cooldownTime = 1000 + (long)(Math.random() * 2000); // 1-3秒冷却
            this.lastActionTime = 0;
            this.lastUpdateTime = System.currentTimeMillis();
            this.lastAction = AIDecision.IDLE;
        }
    }
    
    private static class Player {
        int id;
        String name;
        int level;
        int health;
        float x;
        float y;
        
        public Player(int id, String name, int level, int health, float x, float y) {
            this.id = id;
            this.name = name;
            this.level = level;
            this.health = health;
            this.x = x;
            this.y = y;
        }
    }
    
    private static class NPC {
        int id;
        String name;
        int level;
        int health;
        NPCBehavior behavior;
        
        public NPC(int id, String name, int level, int health, NPCBehavior behavior) {
            this.id = id;
            this.name = name;
            this.level = level;
            this.health = health;
            this.behavior = behavior;
        }
    }
    
    private static class AIManager {
        private Map<Integer, AIUnit> units = new ConcurrentHashMap<>();
        
        public void addAIUnit(AIUnit unit) {
            units.put(unit.id, unit);
        }
        
        public AIUnit getAIUnit(int id) {
            return units.get(id);
        }
    }
    
    // 枚举类型
    private enum NPCBehavior {
        AGGRESSIVE, DEFENSIVE, PASSIVE, PATROL
    }
    
    private enum AIDecision {
        IDLE, ATTACK, DEFEND, MOVE_FORWARD, MOVE_BACKWARD, MOVE_RANDOM, TURN, ESCAPE
    }
    
    private enum Skill {
        ATTACK, DEFEND, HEAL, ESCAPE
    }
    
    /**
     * JUnit 测试方法 - 验证基准测试是否可以正常工作
     */
    @Test
    public void testAIDecisionSetup() {
        // 测试设置是否正确
        assertNotNull(aiManager, "AI manager should not be null");
        assertFalse(aiUnits.isEmpty(), "AI units should not be empty");
        assertFalse(players.isEmpty(), "Players should not be empty");
        assertFalse(npcs.isEmpty(), "NPCs should not be empty");
        
        // 测试方法可以正常运行
        AIDecision decision = benchmarkBasicDecision();
        assertNotNull(decision, "Basic decision should not be null");
        
        Player target = benchmarkTargetSelection();
        // target可能为null，这是正常的（没有目标在范围内）
        
        Skill skill = benchmarkSkillSelection();
        assertNotNull(skill, "Skill selection should not be null");
        
        boolean isReady = benchmarkCooldownManagement();
        // isReady可能是true或false，都是有效的
        
        // 测试AI更新
        benchmarkAIUpdate();
    }
    
    /**
     * JUnit 测试方法 - 验证基准测试方法的性能
     */
    @Test
    public void testAIDecisionPerformance() {
        // 测试基础决策性能
        long startTime = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            benchmarkBasicDecision();
        }
        long duration = System.nanoTime() - startTime;
        
        // 验证在合理时间内完成（2秒内）
        assertTrue(duration < 2_000_000_000L, 
            "Basic AI decision should complete within 2 seconds");
        
        // 测试目标选择性能
        startTime = System.nanoTime();
        for (int i = 0; i < 100; i++) {
            benchmarkTargetSelection();
        }
        duration = System.nanoTime() - startTime;
        
        // 验证在合理时间内完成（2秒内）
        assertTrue(duration < 2_000_000_000L, 
            "Target selection should complete within 2 seconds");
        
        // 测试AI更新性能
        startTime = System.nanoTime();
        for (int i = 0; i < 100; i++) {
            benchmarkAIUpdate();
        }
        duration = System.nanoTime() - startTime;
        
        // 验证在合理时间内完成（3秒内）
        assertTrue(duration < 3_000_000_000L, 
            "AI update should complete within 3 seconds");
    }
    
    /**
     * JMH 基准测试运行方法 - 用于独立运行基准测试
     */
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
            .include(AIDecisionBenchmark.class.getSimpleName())
            .build();
        new Runner(opt).run();
    }
}